#pragma once

#include "Singleton.h"
#include "Character.h"
#include "struct/teleport.h"

class MapServerProxy;

class TeleportMgr : public Singleton<TeleportMgr>
{
public:
	TeleportMgr();
	virtual ~TeleportMgr();

	void Tick();

	void HandleLoginRequest(ObjGUID playerGuid,
		ObjGUID instOwner, InstGUID instGuid, const vector3f1f& pos,
		TeleportType type);
	void HandleTeleportRequest(ObjGUID playerGuid,
		ObjGUID instOwner, InstGUID instGuid, const vector3f1f& pos,
		TeleportType type, uint32 flags, const std::string_view& args);

	void HandleBeginEnterInstanceRespon(GErrorCode errCode, ObjGUID playerGuid,
		ObjGUID instOwner = ObjGUID_NULL, InstGUID instGuid = InstGUID_NULL,
		const vector3f1f& pos = vector3f1f_NULL);
	void HandleLeaveMapRespon(bool isSucc,
		ObjGUID playerGuid, InstGUID instGuid, const vector3f1f& pos);

	void HandlePlayerLoadMapFinish(ObjGUID playerGuid);
	void HandleCharacterSaved(ObjGUID playerGuid);

	void TeleportRequestFailed(ObjGUID playerGuid, GErrorCode errCode);
	void PlayerLoadRequestFailed(ObjGUID playerGuid, GErrorCode errCode);

	void OnEnterToTargetMS(MapServerProxy* pTargetServer, Character* pChar);
	void OnLeaveFromSourceMS(MapServerProxy* pSourceServer, Character* pChar);

	bool HasTeleportInfo(ObjGUID playerGuid) const;
	void RemoveTeleportInfo(ObjGUID playerGuid);
	bool HasPlayerLoadInfo(ObjGUID playerGuid) const;
	void RemovePlayerLoadInfo(ObjGUID playerGuid);

	void DisposeMapServerOffline(MapServerProxy* pMapServer);

private:
	struct ExtTeleportInfo : public CharTeleportInfo {
		Character* pChar = NULL;
		bool isOpLeave = false;
		std::string args;
	};
	struct ExtPlayerLoadInfo : public CharLoadInfo {
		Character* pChar = NULL;
		time_t expireTime = 0;
		bool isLoaded = false;
		bool isSaved = false;
	};

	void BeginEnterInstance(const ExtTeleportInfo& tpInfo);
	void ReformTeleportRequest(const ExtTeleportInfo& tpInfo);

	void TryInitNewInstance(const ExtTeleportInfo& tpInfo);
	void TryEnterNewInstance(const ExtPlayerLoadInfo& plInfo);

	bool LeaveFromSourceMS(ObjGUID playerGuid);
	void LoadMapToEnterTargetMS(ObjGUID playerGuid);
	void SendToClientToLeaveMap(ObjGUID playerGuid);
	void SendToClientToLogoutGame(ObjGUID playerGuid);

	ExtTeleportInfo* GetTeleportInfo(ObjGUID playerGuid);
	ExtPlayerLoadInfo* GetPlayerLoadInfo(ObjGUID playerGuid);

	ObjGUID GetInstanceOwner(const ExtTeleportInfo& tpInfo) const;
	InstGUID GetInstanceGuid(const ExtTeleportInfo& tpInfo) const;

	std::unordered_map<ObjGUID, ExtTeleportInfo> m_teleportInfos;
	std::unordered_map<ObjGUID, ExtPlayerLoadInfo> m_playerLoadInfos;
};

#define sTeleportMgr (*TeleportMgr::instance())
